#ifndef ZDENSITY_PEAK_ALGORITHM_H_
#define ZDENSITY_PEAK_ALGORITHM_H_

#include "../Common/GlobalDefines.h"
#include "ZMLAlgorithm.h"
#include "../Math/FLAnnWarper.h"

GLOBAL_NAMESPACE_BEGIN

namespace MLAlgorithms
{
    class DensityPeak : public MLAlgorithm
    {
        struct Param
        {
            // calculated params
            double dc;
            double maxDist;
            // input params
            double dcScale;
            double thresholdGap;
        };
    public:
        DensityPeak();
        ~DensityPeak();

        void init(const Eigen::MatrixXd& data);
        void setData(const Eigen::MatrixXd& data);
        bool commit();

        inline int                  getPointSize();
        inline int                  getPointDim();
        inline Eigen::MatrixXd      getPoints()     { return data_; }
        inline std::vector<double>  getRhos()       { return rhos_; }
        inline std::vector<double>  getDeltas()     { return deltas_; }
        inline std::vector<double>  getRhoTimesDeltas() { return rhoTimesDeltas_; }
        inline double getRhoTimesDeltasAt(int idx)  { return rhoTimesDeltas_[idx]; }
        inline std::vector<int>     getClusterIdx() { return clusterIds_;  }

        inline void setSCScaleParam(double scale = 10)  { param_.dcScale = scale; }
        inline void setGapParam(double gap = 10)        { param_.thresholdGap = gap; }

        // file IO
        bool readFromFile(const char* fileName);
        bool saveResultToFile(const char* fileName);
        bool readResultFromFile(const char* fileName);
        //bool saveCluterIdsToFile(const char* fileName);

        bool analyseResult();
        bool clusterAll();

    private:
        void destroy();

    private:
        void computeParams_old();
        void computeParams();
        void computeRho();
        void computeDelta();
        void computeTimes();

        void computeMaxDist();

    private:
        Eigen::MatrixXd data_;
        Param param_;

        FLAnnWarper<MATH::L2_Distance> *pAnn_;
        //FLAnnWarper<MATH::L2_Distance_Inverse> *pAnnRho_;
        FLAnnWarper<MATH::L2_Distance> *pAnnRho_;
        std::vector<double> rhos_;
        std::vector<double> deltas_;
        std::vector<double> rhoTimesDeltas_;

        std::vector<int> clusterCenterIds_; // the center data's IDs
        std::vector<int> clusterIds_;       // which center the point belonging to
    };
}

GLOBAL_NAMESPACE_END

#endif//ZDENSITY_PEAK_ALGORITHM_H_